/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = informix_core.c                                                 */
/*  NOTE      = TDS协议解析                                                   */
/*  DATE      = 2014/05/27 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "frservice_comm.h"
#include "informix_core.h"
#include "informix_common.h"
#include "informix_request.h"
#include "informix_response.h"
#include "config.h"

#define INFORMIX_HASH_COUNT          100    /* 最大hash个数 */
#define INFORMIX_MAX_BUFF_SIZE       1024 * 1024

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  初始化私有SQL Server session
*  ARGS     :  p_st_session(SQL Server私有session)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :
*******************************************************************************/
static int __informix_init_private(L7_session *p_st_session)
{
    Frhash_header *p_st_prepare_hash = NULL;                 /* prepare hash */
    L7_fragment_informix *p_st_fragment = NULL;              /* 分片包相关数据 */
    L7session_informix  *p_st_informix_conn = NULL;          /* 链接信息 */
    L7session_informix_private *p_st_private_session = NULL; /* informix私有session */

    /* 申请整个私有session结构的内存 */
    p_st_private_session = (L7session_informix_private *)frmalloc(sizeof(L7session_informix_private));
    if (p_st_private_session == NULL)
    {
        goto error;
    }
    memset(p_st_private_session, 0x00, sizeof(L7session_informix_private));

    /* 申请链路信息结构内存 */
    p_st_informix_conn = (L7session_informix *)frmalloc(sizeof(L7session_informix));
    if (p_st_informix_conn == NULL)
    {
        goto error;
    }
    memset(p_st_informix_conn, 0x00, sizeof(L7session_informix));

    /* 申请分片包信息结构内存 */
    p_st_fragment = (L7_fragment_informix *)frmalloc(sizeof(L7_fragment_informix));
    if (p_st_fragment == NULL)
    {
        goto error;
    }
    memset(p_st_fragment, 0x00, sizeof(L7_fragment_informix));
    p_st_fragment->i_need_req_resp = INFORMIX_DIRECT_REQUEST;

    /* 创建prepare hash */
    p_st_prepare_hash = frhash2_create2(INFORMIX_HASH_COUNT);
    if (p_st_prepare_hash == NULL)
    {
        goto error;
    }

    /* 初始化信息 */
    p_st_informix_conn->i_endian = BYTE_BIG_ENDIAN;
    p_st_informix_conn->i_flt_type = FRTDS_FLT_IEEE_LO;
    p_st_informix_conn->i_ver_get_flg = FR_NO;
    p_st_informix_conn->arr_ver_info[INFORMIX_903_IDX] = 1;
    p_st_informix_conn->arr_ver_info[INFORMIX_902_IDX] = 1;
    p_st_informix_conn->arr_ver_info[INFORMIX_USVER_IDX] = 1;
    p_st_informix_conn->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
    p_st_informix_conn->arr_ver_info[INFORMIX_ASF_IDX] = 1;
    p_st_informix_conn->arr_ver_info[INFORMIX_GLS_IDX] = 1;

    /* 设置初始化结构 */
    p_st_private_session->p_st_sess = p_st_informix_conn;
    p_st_private_session->p_st_fragment = p_st_fragment;
    p_st_private_session->p_hash_prepare = p_st_prepare_hash;
    p_st_session->p_session_private = p_st_private_session;
    return FR_SUCC;

error:
    informix_free((char **)(&p_st_private_session));
    informix_free((char **)(&p_st_informix_conn));
    informix_free((char **)(&p_st_fragment));
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  取得完整的packet包
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  FR_FAIL (true)
*              FR_SUCC (false)
*  NOTE     :  解析失败后需要释放p_st_private里的request/response/fragment信息
*******************************************************************************/
static int __informix_set_analysis_data(Conntrack *p_st_conn
                                        , Apm_packet *p_st_packet
                                        , L7session_informix_private *p_st_private)
{
    int i_ret = FR_SUCC;
    L7_fragment_informix *p_st_fragment = p_st_private->p_st_fragment;
    int i_req_resp = 0;

    /* 取得方向 */
    i_req_resp = frcap_get_cs_direction(p_st_conn, p_st_packet->src_ip
                                       , p_st_packet->src_port);
    /* 创建bytebuffer */
    if (p_st_fragment->p_st_data == NULL)
    {
        /* 做成bytebuffer */
        p_st_fragment->p_st_data = bytebuff_creat();
        if (p_st_fragment->p_st_data == NULL)
        {
            frdbg("create bytebuff failed\n");
            return FR_FAIL;
        }
        /* 设置第一个分片包时间 */
        p_st_fragment->st_first_timestamp = p_st_packet->st_timestamp;
        /* 设置最后一个分片包时间 */
        p_st_fragment->st_end_timestamp = p_st_packet->st_timestamp;

        i_ret = bytebuff_add(p_st_fragment->p_st_data
                            , p_st_packet->p_payload
                            , p_st_packet->ui_payload_len);
        if (i_ret != FR_SUCC)
        {
            frdbg("add data to bytebuff failed\n");
            return FR_FAIL;
        }
        //if (i_req_resp == FR_CLIENT_IP_PORT)
        //{
        //    p_st_fragment->i_need_req_resp = INFORMIX_DIRECT_REQUEST;
        //}
        //else if (i_req_resp == FR_SRV_IP_PORT)
        //{
        //    p_st_fragment->i_need_req_resp = INFORMIX_DIRECT_RESPONSE;
        //}
        //else
        //{
        //    frdbg("direct unknow\n");
        //    return FR_FAIL;
        //}
    }
    else
    {
        if((i_req_resp == FR_CLIENT_IP_PORT
            && p_st_fragment->i_need_req_resp == INFORMIX_DIRECT_REQUEST)
          || (i_req_resp == FR_SRV_IP_PORT
            && p_st_fragment->i_need_req_resp == INFORMIX_DIRECT_RESPONSE))
        {
            /* 设置最后一个分片包时间 */
            p_st_fragment->st_end_timestamp = p_st_packet->st_timestamp;
            /* 对于超长数据，不继续在做解析 */
            if (bytebuff_length(p_st_fragment->p_st_data) >= INFORMIX_MAX_BUFF_SIZE)
            {
                frdbg("too large size!\n");
                return FR_FAIL;
            }

            i_ret = bytebuff_add(p_st_fragment->p_st_data
                                , p_st_packet->p_payload
                                , p_st_packet->ui_payload_len);
            if (i_ret != FR_SUCC)
            {
                frdbg("add data to bytebuff failed\n");
                return FR_FAIL;
            }
        }
        else if (i_req_resp == FR_DIRECT_UNKNOWN)
        {
            frdbg("direct unknow\n");
            return FR_FAIL;
        }
        else /* 上一个request或者response不完整 */
        {
            /* 销毁遗留信息 */
            informix_destroy_curr_info(p_st_private);
            /* 创建新的解析数据 */
            p_st_fragment->p_st_data = bytebuff_creat();
            if (p_st_fragment->p_st_data == NULL)
            {
                frdbg("create bytebuff failed\n");
                return FR_FAIL;
            }
            /* 设置第一个分片包时间 */
            p_st_fragment->st_first_timestamp = p_st_packet->st_timestamp;
            /* 设置最后一个分片包时间 */
            p_st_fragment->st_end_timestamp = p_st_packet->st_timestamp;

            i_ret = bytebuff_add(p_st_fragment->p_st_data
                                , p_st_packet->p_payload
                                , p_st_packet->ui_payload_len);
            if (i_ret != FR_SUCC)
            {
                frdbg("add data to bytebuff failed\n");
                return FR_FAIL;
            }
        }
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是TDS协议
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_packet(入力数据包)
*  RTN      :  APM_L7_IS_NO   (NO)
*              APM_L7_IS_YES  (YES)
*  NOTE     :
*******************************************************************************/
int informix_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = FR_SUCC;
    uint16_t u16_value = 0;
    uint16_t u16_count = 0;
    uint16_t u16_2byte_head = 0;
    uint8_t u8_type = 0;
    int i_is_request = FR_NO;
    unsigned int ui_len = 0;
    char *p_data = NULL;
    Frbyte_Packet *p_st_data = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_packet->p_payload == NULL)
        return APM_L7_IS_NO;

    ui_len = p_st_packet->ui_payload_len;           /* packet数据长度 */
    p_data = p_st_packet->p_payload;                /* packet数据内容 */

    if (ui_len < 2)
    {
        goto error;
    }
    /* 创建bytebuff */
    p_st_data = bytebuff_creat();
    if (p_st_data == NULL)
    {
        goto error;
    }
    i_ret = bytebuff_add(p_st_data, p_data, ui_len);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* 取得header code */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_2byte_head, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }
    /* 首先判断是否是login */
    if (ui_len == u16_2byte_head
        && p_data[ui_len -2] == 0x00
        && p_data[ui_len -1] == 0x7F)
    {
        i_ret = bytebuff_get_char(p_st_data, &u8_type);
        bytebuff_free(&p_st_data);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }

        switch (u8_type)
        {
            case 1:
                /* 设置request方向 */
                if(frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
                {
                    i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip , p_st_packet->dst_port);
                    if (i_ret != FR_SUCC)
                    {
                        frdbg("Set server ip and port failed!\n");
                        return APM_L7_IS_NO;
                    }
                }
                return APM_L7_IS_YES;

            case 2:
            case 3:
                /* 设置response方向 */
                if(frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
                {
                    i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
                    if (i_ret != FR_SUCC)
                    {
                        frdbg("Set server ip and port failed!\n");
                        return APM_L7_IS_NO;
                    }
                }
                return APM_L7_IS_YES;

            default:
                goto error;
        }
    }

    /* check除了login之外的 */
    while (u16_2byte_head != INFORMIX_MSG_TP_EOT)
    {
        switch(u16_2byte_head)
        {
            case INFORMIX_MSG_TP_COMMAND:
                /* 跳过2byte */
                i_ret = bytebuff_skip(p_st_data, 2);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }
                /* 取得command字符串 */
                i_ret = informix_skip_2byte_padded(p_st_data);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    goto error;
                }
                i_ret = bytebuff_skip(p_st_data, 2 + 2 + 2);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_PREPARE:
                /* 跳过2byte */
                i_ret = bytebuff_skip(p_st_data, 2);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }
                /* 取得command字符串 */
                i_ret = informix_skip_2byte_padded(p_st_data);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    goto error;
                }
                i_ret = bytebuff_skip(p_st_data, 2 + 2);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_CURNAME:
                /* skip cursorname */
                i_ret = informix_skip_2byte_padded(p_st_data);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    goto error;
                }
                i_ret = bytebuff_get_short(p_st_data, 2, &u16_value, BYTE_BIG_ENDIAN);
                if (i_ret != FR_SUCC)
                {
                    goto error;
                }
                while (1)
                {
                    if (u16_value == 6)
                    {
                        break;
                    }
                    else if (u16_value == 108 || u16_value == 24 || u16_value == 43)
                    {
                        i_ret = bytebuff_get_short(p_st_data, 2, &u16_value, BYTE_BIG_ENDIAN);
                        if (i_ret != FR_SUCC)
                        {
                            goto error;
                        }
                    }
                    else
                    {
                        goto error;
                    }
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_ID:
                i_ret = bytebuff_skip(p_st_data, 2);
                if (i_ret != FR_SUCC)
                {
                    goto error;
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_CLOSE:
            case INFORMIX_MSG_TP_RELEASE:
            case INFORMIX_MSG_TP_EXECUTE:
            case INFORMIX_MSG_TP_BEGIN:
            case INFORMIX_MSG_TP_DBLIST:
            case INFORMIX_MSG_TP_XCOMMIT:
            case INFORMIX_MSG_TP_XROLLBACK:
            case INFORMIX_MSG_TP_CIDESCRIBE:
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_NFETCH:
                i_ret = bytebuff_skip(p_st_data, 6);
                if (i_ret != FR_SUCC)
                {
                    goto error;
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_DBOPEN: //(24)36
                i_ret = informix_skip_2byte_padded(p_st_data);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    goto error;
                }
                i_ret = bytebuff_skip(p_st_data, 2);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_INFO: //(51)81
                i_ret = bytebuff_get_short(p_st_data, 2, &u16_value, BYTE_BIG_ENDIAN);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }

                switch (u16_value)
                {
                    case 0:
                        /* check长度是否足够 */
                        if (bytebuff_remaining(p_st_data) < 2)
                        {
                            goto error;
                        }
                        bytebuff_skip(p_st_data, 2);
                        break;

                    case 1:
                        /* check长度是否足够 */
                        if (bytebuff_remaining(p_st_data) < 2 + 2)
                        {
                            goto error;
                        }
                        bytebuff_skip(p_st_data, 2 + 2);
                        break;

                    case 6:
                        /* check长度是否足够 */
                        if (bytebuff_remaining(p_st_data) < 2 + 2 + 2)
                        {
                            goto error;
                        }
                        bytebuff_skip(p_st_data, 2 + 2);
                        /* 取得env count数 */
                        i_ret = bytebuff_get_short(p_st_data, 2, &u16_count, BYTE_BIG_ENDIAN);
                        if (i_ret != FR_SUCC)
                        {
                            goto error;
                        }
                        while (u16_count--)
                        {
                            /* 跳过env */
                            i_ret = informix_skip_2byte_padded(p_st_data);
                            if (i_ret != APM_L7_ANALYZE_SUCC)
                            {
                                goto error;
                            }
                        }
                        /* check长度是否足够 */
                        if (bytebuff_remaining(p_st_data) < 2 + 2)
                        {
                            goto error;
                        }
                        bytebuff_skip(p_st_data, 2 + 2);
                        break;

                    default:
                        goto error;
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_GETROUTINE: //(65)101
                /* skip first 2byte */
                i_ret = bytebuff_skip(p_st_data, 3);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }
                /* 跳过protocols */
                i_ret = informix_skip_2byte_padded(p_st_data);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    goto error;
                }
                /* skip last 2byte */
                i_ret = bytebuff_skip(p_st_data, 3);
                if (i_ret != FR_SUCC)
                {
                   goto error;
                }
                i_is_request = FR_YES;
                break;

            case INFORMIX_MSG_TP_TUPLE:
                /* skip first 2byte */
                i_ret = bytebuff_skip(p_st_data, 2);
                if (i_ret != FR_SUCC)
                {
                    goto error;
                }
                i_ret = informix_skip_4byte_padded(p_st_data);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    goto error;
                }
                break;

            case INFORMIX_MSG_TP_DONE:
                /* skip warning */
                i_ret = bytebuff_skip(p_st_data, 2 + 4 + 4 + 4);
                if (i_ret != FR_SUCC)
                {
                    goto error;
                }
                break;

            case INFORMIX_MSG_TP_COST:
                i_ret = bytebuff_skip(p_st_data, 4 + 4);
                if (i_ret != FR_SUCC)
                {
                    goto error;
                }
                break;

            case INFORMIX_MSG_TP_EXFPROUTINE: //(66)102 todo
            case INFORMIX_MSG_TP_PROTOCOLS: //(7E)126 todo
                frdbg("todo\n");
                goto error;
                break;

            default:
                frdbg("todo\n");
                goto error;
        }

        /* 取得下一个type */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_2byte_head, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }
    }

    /* 不已[\x000C]结尾 */
    if (bytebuff_remaining(p_st_data))
    {
        goto error;
    }
    bytebuff_free(&p_st_data);
    /* 设置方向 */
    if(frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        if (i_is_request == FR_NO)
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
        else
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip , p_st_packet->dst_port);
        if (i_ret != FR_SUCC)
        {
            frdbg("Set server ip and port failed!\n");
            return APM_L7_IS_NO;
        }
    }

    frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
    return APM_L7_IS_YES;

error:
    bytebuff_free(&p_st_data);
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*******************************************************************************
*  FUNC     :  SQL Server的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  参照module.h
*  NOTE     :
*******************************************************************************/
int informix_analysis(Conntrack *p_st_conn
                     , Apm_packet *p_st_packet
                     , Frhash_header *p_st_hash_report)
{
    int i_ret = FR_SUCC;
    int i_req_resp = FR_DIRECT_UNKNOWN;              /* 请求方向 */
    L7_session *p_st_session = NULL;                 /* L7session */
    L7session_informix_private *p_st_private = NULL; /* informix的私有数据 */

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
    {
        frdbg("Call frct_get_session failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /*
    * 如果入力p_st_packet是FIN包, 说明本次informix的connection结束,
    * 释放本次session信息. 如果入力p_st_packet是SYN包,说明新的informix的
    * connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN
        || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        /* 销毁所有相关本次informix的connection的数据 */
        informix_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    /* 本次链路的第一个有效packet包,创建链路 */
    if (p_st_session->p_session_private == NULL)
    {
        //frdbg("=======start parse informix=========\n");
        /* 初始化SQL Server的私有数据 */
        i_ret = __informix_init_private(p_st_session);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call __informix_init_private failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        /* 设置session ID */
        fruuid(p_st_session->arr_session_id);
    }
    p_st_private = (L7session_informix_private *)p_st_session->p_session_private;

    /* 设置解析数据 */
    i_ret = __informix_set_analysis_data(p_st_conn, p_st_packet, p_st_private);
    if (i_ret != FR_SUCC)
    {
        frdbg("set analysis data failed\n");
        informix_destroy_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 取得请求/响应方向 */
    i_req_resp = frcap_get_cs_direction(p_st_conn, p_st_packet->src_ip
                                       , p_st_packet->src_port);
    /* 解析request */
    if (i_req_resp == FR_CLIENT_IP_PORT)
    {
        i_ret = informix_parse_request(p_st_conn, p_st_private
                                      , p_st_hash_report);
    }
    /* 解析response */
    else if (i_req_resp == FR_SRV_IP_PORT)
    {
        if (p_st_private->p_st_req)
        {
            if (p_st_private->p_st_req->i_req_type == INFORMIX_MSG_TP_LOGIN)
            {
                i_ret = informix_parse_login_resp(p_st_conn, p_st_private);
            }
            else
            {
                i_ret = informix_parse_response(p_st_conn, p_st_private
                                               , p_st_hash_report);
            }
        }
        else
        {
            frdbg("there is no request before!\n");
            i_ret = APM_L7_ANALYZE_FAIL;
        }
    }

    /* 解析出错 */
    if (i_ret == APM_L7_ANALYZE_FAIL)
    {
        frdbg("Prase packet failed!\n");
        informix_destroy_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(informix的私有session数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int informix_session_destroy(void *p_private_session)
{
    L7session_informix_private *p_st_private = (L7session_informix_private *)p_private_session;

    /* 判断session是否为空 */
    if (p_st_private == NULL)
    {
        return FR_SUCC;
    }

    /* 销毁session数据 */
    if (p_st_private->p_st_sess)
    {
        informix_destroy_session(&(p_st_private->p_st_sess));
    }

    /* 销毁request数据 */
    if (p_st_private->p_st_req)
    {
        informix_destroy_request(&(p_st_private->p_st_req));
    }

    /* 销毁response数据 */
    if (p_st_private->p_st_resp)
    {
        informix_destroy_response(&p_st_private->p_st_resp);
    }

    /* 销毁分片数据 */
    if (p_st_private->p_st_fragment)
    {
        informix_destroy_fragment(&p_st_private->p_st_fragment);
    }

    /* 销毁prepare数据 */
    frhash2_free2(p_st_private->p_hash_prepare, frdb_statement_node_free);
    p_st_private->p_hash_prepare = NULL;

    frfree(p_st_private);

    return FR_SUCC;
}
